package org.infodavid.common.impl.services;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.joda.time.DateTimeZone;

import org.infodavid.common.model.IApplicationSettings;
import org.infodavid.common.model.IUser;
import org.infodavid.common.model.IUserSession;
import org.infodavid.common.persistence.PersistenceSession;
import org.infodavid.common.services.ApplicationSettingsService;
import org.infodavid.common.services.IApplicationContext;

/**
 * The Class DefaultApplicationContext.
 */
public class DefaultApplicationContext implements IApplicationContext {

	/** The Constant log. */
	private static final Log LOGGER = LogFactory.getLog(DefaultApplicationContext.class);

	/** The persistence session. */
	private transient PersistenceSession persistenceSession;

	/** The properties. */
	private final Map<String,Serializable> properties;

	/** The application settings. */
	private IApplicationSettings settings = null;

	/** The user. */
	private IUser user = null;

	/** The user session. */
	private IUserSession userSession = null;

	/**
	 * The Constructor.
	 * @param session the session
	 */
	public DefaultApplicationContext(final PersistenceSession session) {
		properties = new HashMap<String,Serializable>();
		persistenceSession = session;

		if (session == null) {
			LOGGER.warn("Passed PersistenceSession is null");
		}
	}

	/**
	 * The Constructor.
	 * @param session the session
	 */
	protected DefaultApplicationContext(final Map<String,Serializable> props,
	    final PersistenceSession session) {
		if (props == null) {
			properties = new HashMap<String,Serializable>();
		}
		else {
			properties = props;
		}

		persistenceSession = session;

		if (session == null) {
			LOGGER.warn("Passed PersistenceSession is null");
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.auth.services.IApplicationContext#clear()
	 */
	public void clear() {
		synchronized (this) {
			getProperties().clear();
			setUser(null);
			setUserSession(null);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.services.IApplicationContext#getPersistenceSession()
	 */
	public PersistenceSession getPersistenceSession() {
		return persistenceSession;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.services.IApplicationContext#getProperties()
	 */
	public Map<String,Serializable> getProperties() {
		return properties;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.services.IApplicationContext#getSettings()
	 */
	public IApplicationSettings getSettings() {
		return settings;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.services.IApplicationContext#getUser()
	 */
	public IUser getUser() {
		final IUser result;

		if (userSession == null) {
			result = user;
		}
		else {
			result = userSession.getUser();
		}

		return result;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.services.IApplicationContext#getUserSession()
	 */
	public IUserSession getUserSession() {
		return userSession;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.services.IApplicationContext#getLocale()
	 */
	@Override
	public Locale getLocale() {
		Locale result;

		if (user == null) {
			result = ApplicationSettingsService.getInstance().getDefaultLocale(this);
		}
		else {
			result = user.getLocale();
		}

		return result;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.services.IApplicationContext#getTimeZone()
	 */
	@Override
	public DateTimeZone getTimeZone() {
		DateTimeZone result;

		if (user == null) {
			result = ApplicationSettingsService.getInstance().getDefaultTimeZone(this);
		}
		else {
			result = user.getTimeZone();
		}

		return result;
	}

	public void setPersistenceSession(final PersistenceSession session) {
		persistenceSession = session;
	}

	/**
	 * Sets the user.
	 * @param value the user to set
	 * @return the application context
	 */
	public void setUser(final IUser value) {
		user = value;
	}

	/**
	 * Sets the user session.
	 * @param value the user session to set
	 * @return the application context
	 */
	public void setUserSession(final IUserSession value) {
		userSession = value;

		if (value != null) {
			user = userSession.getUser();
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.services.IApplicationContext#setSettings(org.infodavid.common.model.
	 * IApplicationSettings)
	 */
	public void setSettings(final IApplicationSettings value) {
		settings = value;
	}

	/*
	 * See super class or interface. (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		final StringBuilder builder = new StringBuilder();

		builder.append(super.toString());
		builder.append("DefaultApplicationContext [persistenceSession=");
		builder.append(persistenceSession);
		builder.append(", properties=");
		builder.append(properties);
		builder.append(", settings=");
		builder.append(settings);
		builder.append(", user=");
		builder.append(user);
		builder.append(", userSession=");
		builder.append(userSession);
		builder.append("]");

		return builder.toString();
	}
}
